package com.hzhc.configuration;

import lombok.RequiredArgsConstructor;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: GlobalTransactionConfig
 * @Description:全局性事物管理
 * @version 1.0
 * @author: duanhm
 * @Date: 2019/11/29 11:09:59
 * 
 */
@Aspect
@Configuration
@RequiredArgsConstructor
@EnableTransactionManagement
public class GlobalTransactionConfig {
	// 写事务的超时时间为4秒
	private static final int TX_METHOD_TIMEOUT = 600;

	// restful包下所有service包或者service的子包的任意类的任意方法
	private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.hzhc.service.*.*(..))";


	private final PlatformTransactionManager transactionManager;

	@SuppressWarnings("deprecation")
	@Bean
	public TransactionInterceptor txAdvice() {

		/**
		 * 这里配置只读事务
		 */
		RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
		readOnlyTx.setReadOnly(true);
		readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

		/**
		 * 必须带事务 当前存在事务就使用当前事务，当前不存在事务,就开启一个新的事务
		 */
		RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
		// 检查型异常也回滚
		requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
		requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		requiredTx.setTimeout(TX_METHOD_TIMEOUT);

		/***
		 * 无事务地执行，挂起任何存在的事务
		 */
		RuleBasedTransactionAttribute noTx = new RuleBasedTransactionAttribute();
		noTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);

		Map<String, TransactionAttribute> txMap = new HashMap<>();
		// 只读事务
		txMap.put("get*", readOnlyTx);
		txMap.put("query*", readOnlyTx);
		txMap.put("find*", readOnlyTx);
		txMap.put("list*", readOnlyTx);
		txMap.put("count*", readOnlyTx);
		txMap.put("exist*", readOnlyTx);
		txMap.put("search*", readOnlyTx);
		txMap.put("fetch*", readOnlyTx);
		// 无事务
		txMap.put("noTx*", noTx);
		// 写事务
		txMap.put("add*", requiredTx);
		txMap.put("save*", requiredTx);
		txMap.put("insert*", requiredTx);
		txMap.put("update*", requiredTx);
		txMap.put("modify*", requiredTx);
		txMap.put("delete*", requiredTx);
		txMap.put("del*", requiredTx);
		txMap.put("hcseq*", requiredTx);
		// order_nextval
		NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
		source.setNameMap(txMap);

		return new TransactionInterceptor(transactionManager, source);
	}

	@Bean
	public Advisor txAdviceAdvisor() {
		AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
		pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
		return new DefaultPointcutAdvisor(pointcut, txAdvice());
	}

}
